<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <style>
        header {
            display: block;
            margin: 0 auto;
            width: 100%;
            text-align: center;
        }

        header h1 {
            font-family: Arial;
            font-size: 40px;
            font-weight: bold;
        }

        header #newGameButton {
            display: block;
            margin: 20px auto;
            width: 100px;
            padding: 10px 10px;
            background-color: #8f7a66;
            font-family: Arial;
            color: white;
            border-radius: 10px;
            text-decoration: none;
        }

        header #newGameButton:hover {
            background-color: #9f8b77;
        }

        header p {
            font-family: Arial;
            font-size: 25px;
            margin: 20px auto;
        }

        #grid-container {
            width: 460px;
            height: 460px;
            padding: 20px;
            background-color: #bbada0;
            margin: 50px auto;
            border-radius: 10px;
            position: relative;

        }

        .grid-cell {
            width: 100px;
            height: 100px;
            border-radius: 6px;
            background-color: #ccc0b3;
            position: absolute;
        }

        .number-cell {
            font-family: Arial;
            font-weight: bold;
            font-size: 60px;
            line-height: 100px;
            text-align: center;
            border-radius: 6px;
            background-color: #ccc0b3;
            position: absolute;
        }
    </style>

    <script>
        var board = new Array();
        var gameOver = false;//true为结束
        var score = 0;


        function newGame() {
            init();
            generateOneNumber();
            generateOneNumber();
            console.log(board);
        }

        function init() {
            //定义二维数组，小格子的值都为0;
            for (var i = 0; i < 4; i++) {
                board[i] = new Array();
                for (var j = 0; j < 4; j++) {
                    board[i][j] = 0;
                    var gridCell = document.getElementsByClassName('grid-cell-' + i + '-' + j)[0];
                    gridCell.style.top = i * 120 + 20 + 'px'
                    gridCell.style.left = j * 120 + 20 + 'px'
                }
            }

            updateBoardView();

        }


        //刷新格子
        function updateBoardView() {
            var parent = document.getElementById('grid-container');
            for (var i = 0; i < 4; i++) {
                for (var j = 0; j < 4; j++) {
                    if (document.getElementById('number-cell-' + i + '-' + j) != null) {
                        document.getElementById('number-cell-' + i + '-' + j).remove();
                    }

                    var div = document.createElement('div');
                    parent.appendChild(div);

                    div.setAttribute('class', 'number-cell');
                    div.setAttribute('id', 'number-cell-' + i + '-' + j);

                    if (board[i][j] == 0) {
                        div.style.width = 0;
                        div.style.height = 0;
                        div.style.top = i * 120 + 80 + 'px';
                        div.style.left = j * 120 + 80 + 'px';
                        div.style.backgroundColor = '#ccc0b3';
                    }
                    else {
                        div.style.width = '100px';
                        div.style.height = '100px';
                        div.style.top = i * 120 + 20 + 'px';
                        div.style.left = j * 120 + 20 + 'px';
                        div.style.backgroundColor = getBackgroundColor(board[i][j]);
                        div.innerHTML = board[i][j];
                        div.style.color = getNumberColor(board[i][j]);
                    }
                }
            }
        }

        function getBackgroundColor(Number) {
            switch (Number) {
                case 2: return '#eee4da';
                case 4: return '#ede0c8';
                case 8: return '#f2b179';
                case 16: return '#f59563';
                case 32: return '#f67c5f';
                case 64: return '#f65e3b';
                case 128: return '#edcf72';
                case 256: return '#edcc61';
                case 512: return '#9c0';
                case 1024: return '#33b5e5';
                case 2048: return '#09c';
                case 4096: return '#a6c';
                case 8192: return '#93c';
            }
        }

        function getNumberColor(Number) {
            if (Number <= 4) {
                return "#776e65";
            }
            return "white";
        }

        function generateOneNumber() {
            //生成随机的位置
            do {
                var randr = parseInt(Math.floor(Math.random() * 4));
                var randc = parseInt(Math.floor(Math.random() * 4));

            } while (board[randr][randc] != 0);


            //生成随机的数字
            board[randr][randc] = Math.random() < 0.5 ? 2 : 4;

            //更新格子
            showNumberWithAnimation(randr, randc, board[randr][randc]);
            // updateBoardView();


        }

        //动画效果显示随机数
        function showNumberWithAnimation(randr, randc, number) {
            var numbercell = document.getElementById('number-cell-' + randr + '-' + randc);
            numbercell.style.backgroundColor = getBackgroundColor(number);
            numbercell.innerHTML = number;
            numbercell.style.color = getNumberColor(number);
            numbercell.animate([{ width: '0px', height: '0px', left: randc * 120 + 80 + 'px', top: randr * 120 + 80 + 'px' }, { width: '100px', height: '100px', left: randc * 120 + 20 + 'px', top: randr * 120 + 20 + 'px' }], { duration: 50, fill: 'forwards' });

        }

        //上下左右按键触发
        document.onkeydown = function (e) {
            if (gameOver) {
                return;
            }

            //计算前结果，用于跟计算后结果比较，判断是否生成新数字
            var oldBoard = new Array;
            for (var i = 0; i < 4; i++) {
                oldBoard[i] = new Array;
                for (var j = 0; j < 4; j++) {
                    oldBoard[i][j] = board[i][j];
                }
            }


            switch (e.keyCode) {
                case 38:
                    console.log('up');
                    //按键向上，对每一列进行规则运算
                    for (var j = 0; j < 4; j++) {
                        var temp = new Array();
                        var res = new Array();
                        //取每一列的值，转为一个数组
                        for (var i = 0; i < 4; i++) {
                            temp.push(board[i][j]);
                        }

                        //对这个数组进行规则计算，连续相同并不为0的合并，并非零考前排序
                        res = arrayCal(temp);

                        //将结果返回给数组
                        for (var i = 0; i < 4; i++) {
                            board[i][j] = res[i];
                        }

                    }
                    break;
                case 40:
                    console.log('down');
                    //按键向下，对每一列进行规则运算
                    for (var j = 0; j < 4; j++) {
                        var temp = new Array();
                        var res = new Array();
                        //取每一列的值，转为一个数组
                        for (var i = 3; i >= 0; i--) {
                            temp.push(board[i][j]);
                        }

                        //对这个数组进行规则计算，连续相同并不为0的合并，并非零考前排序
                        res = arrayCal(temp);

                        //将结果返回给数组
                        for (var i = 3; i >= 0; i--) {
                            board[i][j] = res[res.length - 1 - i];
                        }

                    }
                    break;
                case 37:
                    console.log('left');
                    //按键向左，对每一行进行规则运算
                    for (var i = 0; i < 4; i++) {
                        var temp = new Array();
                        var res = new Array();
                        //取每一行的值，转为一个数组
                        for (var j = 0; j < 4; j++) {
                            temp.push(board[i][j]);
                        }

                        //对这个数组进行规则计算，连续相同并不为0的合并，并非零考前排序
                        res = arrayCal(temp);

                        //将结果返回给数组
                        for (var j = 0; j < 4; j++) {
                            board[i][j] = res[j];
                        }

                    }
                    break;
                case 39:
                    console.log('right');
                    //按键向右，对每一行进行规则运算
                    for (var i = 0; i < 4; i++) {
                        var temp = new Array();
                        var res = new Array();
                        //取每一行的值，转为一个数组
                        for (var j = 3; j >= 0; j--) {
                            temp.push(board[i][j]);
                        }

                        //对这个数组进行规则计算，连续相同并不为0的合并，并非零考前排序
                        res = arrayCal(temp);

                        //将结果返回给数组
                        for (var j = 3; j >= 0; j--) {
                            board[i][j] = res[res.length - 1 - j];
                        }

                    }
                    break;

            }

            var flag = true; //true 时可以生成 新数字。


            updateBoardView();

            //计算后结果
            var newBoard = new Array;
            for (var i = 0; i < 4; i++) {
                newBoard[i] = new Array;
                for (var j = 0; j < 4; j++) {
                    newBoard[i][j] = board[i][j];
                }
            }
            // console.log(oldBoard,newBoard);

            //计算前跟计算后，若没有任何变化，则不进行生成数字
            if (newBoard.toString() == oldBoard.toString()) {
                flag = false;
            }

            //没有0 空位，则不允许生成新的数字。
            console.log(newBoard);
            if (!isExistZero(newBoard)) {
                console.log('没有空位');
                flag = false;
            }


            if (flag) {
                generateOneNumber();
                console.log('生成完毕');

                //生成完毕，再判断一次是否有0空位，没有的判断是否结束
                if (!isExistZero(board)) {
                    console.log('没有空位');
                    if (isGameOver()) {
                        console.log('游戏结束');
                        alert('游戏结束');
                    }
                }


            }

        }

        //判定是否还有空位
        function isExistZero(arr) {
            console.log(arr);
            let isExistZero = false;  //所有数字不为0
            for (var i = 0; i < 4; i++) {
                if (arr[i].indexOf(0) != -1) {
                    isExistZero = true;
                    console.log('还有空位');
                    return true;
                }
            }
            return isExistZero;
        }

        //所有有数字不为0时,判断游戏是否结束,所，检查上下左右是否有相同数字，都不同，则结束游戏
        function isGameOver() {
            for (var i = 0; i < 4; i++) {
                var notGameOver = false;
                for (var j = 0; j < 4; j++) {
                    if (j < 3 && (board[i][j] == board[i][j + 1])) {
                        notGameOver = true;
                        break;
                    }
                    if (i < 3 && (board[i][j] == board[i + 1][j])) {
                        notGameOver = true;
                        break;
                    }
                }
                if (notGameOver) {
                    break;
                }
            }

            if (notGameOver == false) {
                gameOver = true;
                return true;
            }
        }


        //对这个数组进行规则计算，连续相同并不为0的合并，并非零考前排序
        function arrayCal(temp) {
            for (var i = 0; i < 4; i++) {
                if (temp[i] != 0) {//不为0，判断跟后续的数字是0还是相同，还是不同
                    for (var x = i + 1; x < 4; x++) {
                        if (temp[x] == temp[i] && temp[x] != 0) {
                            temp[i] = 2 * temp[i];
                            score = score + temp[i];
                            document.getElementById('score').innerHTML = score;
                            temp[x] = 0;
                            break;
                        }
                        else if (temp[x] != temp[i] && temp[x] != 0) {
                            break;
                        }
                    }

                }
                else {//0的时候交换数值
                    for (var n = i + 1; n < 4; n++) {
                        if (temp[n] != 0) {
                            temp[i] = temp[n];
                            temp[n] = 0;
                            i--;
                            break;
                        }
                    }
                }
            }
            return temp
        }

    </script>
</head>


<body onload="newGame()">
    <header>
        <h1>2048</h1>
        <a id="newGameButton" href="">New Game</a>
        <p>score:<span id="score">0</span></p>
    </header>
    <div id="grid-container">
        <div class="grid-cell-0-0 grid-cell"></div>
        <div class="grid-cell-0-1 grid-cell"></div>
        <div class="grid-cell-0-2 grid-cell"></div>
        <div class="grid-cell-0-3 grid-cell"></div>
        <div class="grid-cell-1-0 grid-cell"></div>
        <div class="grid-cell-1-1 grid-cell"></div>
        <div class="grid-cell-1-2 grid-cell"></div>
        <div class="grid-cell-1-3 grid-cell"></div>
        <div class="grid-cell-2-0 grid-cell"></div>
        <div class="grid-cell-2-1 grid-cell"></div>
        <div class="grid-cell-2-2 grid-cell"></div>
        <div class="grid-cell-2-3 grid-cell"></div>
        <div class="grid-cell-3-0 grid-cell"></div>
        <div class="grid-cell-3-1 grid-cell"></div>
        <div class="grid-cell-3-2 grid-cell"></div>
        <div class="grid-cell-3-3 grid-cell"></div>
    </div>

</body>

</html>